/** \file vetor.cpp
 *  \brief Implementação dos métodos, operadores e funções definidos na classe vetor, no arquivo vetor.hpp
 *  \author Geraldo Francisco de S. Rebouças | gfs.reboucas@gmail.com
 *  \since 28/11/2012
 *  \version 1.0
 *  \date 02/12/2012 */

#include "vetor.hpp"

vetor::vetor()      {} ///< Contrutor default

vetor::~vetor()     {} ///< Destrutor default

vetor::vetor(int dd){   dim = dd;    trp = false; setNull(dim); }

vetor::vetor(int dd, bool ff)   {    dim = dd;    v.resize(dim);    trp = ff;     setNull(dim); }
/** \fn vetor
 *  \param dd Dimensão do vetor a ser criado
 *  \param ff Tipo do vetor, linha ou coluna */

vetor::vetor(double* vv, int dd, bool ff)
{/** \fn vetor
  *  \param vv Array contendo os elementos do vetor a ser criado
  *  \param dd Dimensão do vetor a ser criado
  *  \param ff Tipo do vetor, linha ou coluna */

    dim = dd;    v.resize(dim);    trp = ff;

    for(signed int i = 0; i < dim; i++)
        v[i] = vv[i];
}

vetor::vetor(valarray <double> vv, bool ff)     {  dim = vv.size();  v = vv;  trp = ff;   }
/** \fn vetor
 *  \param vv valarray de double contendo os elementos do vetor a ser criado
 *  \param dd Dimensão do vetor a ser criado
 *  \param ff Tipo do vetor, linha ou coluna */

vetor::vetor(const vetor &q)    {    dim = q.dim;    trp = q.trp;      v = q.v;   }
/** \fn vetor
 *  \param q vetor a ser copiado */

void vetor::setNull(int a)
{
    dim = a;    v.resize(dim);      trp = false;

    for(signed int i = 0; i < dim; i++)
        v[i] = 0.0;
}

void vetor::show()
{
    if(trp == true)
    {
        for(signed int i = 0; i < dim; i++)
            scout << v[i] << "\t";
            cout << endl;
    } else if(trp == false)
    {
        for(signed int i = 0; i < dim; i++)
            scout << v[i] << endl;
    }
}

void vetor::set(int dd, bool ff)
{/** \fn set
  *  \param dd Dimensão do vetor a ser criado
  *  \param ff Tipo do vetor, linha ou coluna */

    dim = dd;
    v.resize(dim);
    trp = ff;

    for(signed int i = 0; i < dim; i++)
    {
        cout << "Insira o " << i + 1 << " elemento do vetor: ";
        cin >> v[i];
    }
}

double vetor::norma(int w)
{/** \fn norma
  *  \param w Norma desejada */

    double ret = 0.0;

    for(signed int i = 0; i < dim; i++)
        ret += pow(abs(v[i]), w);

    ret = pow(ret, 1.0/w);

    return ret;
}

double vetor::normaInf()  {  double ret = 0.0;  valarray <double> m = abs(v);  ret = m.max();  return ret;   }

vetor& vetor::operator=(const vetor &c)
{
    if(this == &c)
    {
        //
    }
    else
    {
        dim = c.dim;        trp = c.trp;        v = c.v;
    }

    return *this;
}

vetor vetor::operator-()
{
    vetor ret(-1.0*v, trp);
    return ret;
}

vetor& vetor::operator+=(const vetor& q)
{
    *this = *this + q;
    return *this;
}

vetor zero(int k, bool g)
{
    vetor ret(k, g);

    for(signed int i = 0; i < k; i++)
        ret(i) = 0.0;

    return ret;
}

vetor operator*(double k, vetor vv)
{
    int tt = vv.retDim();    valarray<double> temp(tt);

    for(int i = 0; i < tt; i++)
    temp[i] = k*vv(i);

    vetor ret(temp, vv.retTr()); 	return ret;
}

vetor operator*(vetor vv, double k)     {   return k*vv;    }
/** \fn operator*
 *  \brief Perceba que utilizamos a definição da sobrecarga anterior p/ tornarmos o código menor */

vetor operator+(vetor a, vetor b)
{
    valarray<double> temp;

    if(a.retDim() != b.retDim())
    {
        cerr << "Erro! Dimensoes incompativeis! \n";
        abort();
    }
    else
    {
        int tt = a.retDim();        temp.resize(tt);

        for(signed int i = 0; i < tt; i++)
            temp[i] = a(i) + b(i);
    }

    vetor ret(temp, a.retTr());    return ret;
}

vetor operator-(vetor a, vetor b)   {   return a +(-b);     }

double& vetor::operator()(int i)
{
    if(i > retDim() - 1)
    {
        cerr << "operator() \n Erro! Dimensao invalida \n";
        abort();
    }

    return v[i];
}

int vetor::retDim()       {   return dim;  }

bool vetor::retTr()      {   return trp;   }

double operator^(vetor a, vetor b)
{
    double ret = 0.0;

    if(a.retDim() != b.retDim())
    {
        cerr << "Erro! Dimensoes diferentes! \n";
        abort();
    }
    else
    {
        int p = a.retDim();
        for(signed int i = 0; i < p; i++)
            ret += a(i)*b(i);
    }
    return ret;
}

vetor operator*(vetor a, vetor b)
{
    vetor c(3,'c');

    if((a.retDim() > 3) or (b.retDim() > 3))
    {
        cerr << "Erro! Dimensao invalida! \n";
        abort();
    }
    else
    {
        c(0) = a(1)*b(2) - a(2)*b(1);
        c(1) = a(2)*b(0) - a(0)*b(2);
        c(2) = a(0)*b(1) - a(1)*b(0);
    }
    return c;
}

vetor operator*(vetor a, matriz A)
{
    if(a.retDim() != A.retl())
       {
           cerr << "Erro! Dimensoes incoerentes \n";
           abort();
       }
    int ll = a.retDim();
    int cc = A.retc();

    vetor ret(cc, a.retTr());

    for(signed int i = 0; i < ll; i++)
        for(signed int j = 0; j < cc; j++)
            ret(j) += A(i,j)*a(i);

    return ret;
}

vetor operator*(matriz A, vetor a)
{
    if(a.retDim() != A.retc())
       {
           cerr << "Erro! Dimensoes incoerentes \n";
           abort();
       }
    int ll = A.retc();
    int cc = a.retDim();

    vetor ret(ll, a.retTr());

    for(signed int i = 0; i < ll; i++)
        for(signed int j = 0; j < cc; j++)
            ret(i) += A(i,j)*a(j);

    return ret;
}

ostream& operator<<(ostream& os, vetor x)
{
    for(signed int i = 0; i < x.retDim(); i++)
        os << x(i) << "\t";

    return os;
}

vetor vetor::minivec(int a, int b)
{
    if((b <= a) or (a < 0) or (b > dim - 1))
    {
        cerr << "Erro! Indices incompatíveis! \n";
        abort();
    }

    int t = b - a + 1;
    vetor ret(t, trp);

    for(signed int i = 0; i < t; i++)
        ret(i) = v[i + a];

    return ret;
}
